package qj.app.console;

import static qj.util.SwingUtil.panel;
import static qj.util.SwingUtil.panel_border;
import static qj.util.SwingUtil.scrollPane;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.io.File;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import qj.app.console.Config.Console;
import qj.app.console.invoker.Invoker;
import qj.tool.jna.KeyboardHandler;
import qj.ui.DesktopUI4;
import qj.util.IOUtil;
import qj.util.SwingUtil;
import qj.util.SystemUtil;
import qj.util.ThreadUtil;
import qj.util.appCommon.swing.AppFrame;
import qj.util.funct.F0;
import qj.util.funct.P0;
import qj.util.funct.P1;
import qj.util.swing.ConsolePane;

public class ConsoleMain {
	
	public static void main(String[] args) {
		final File configFile = new File("config.dat");
		final Config config = getConfig(configFile);
		
		config.saveF = new P0() {public void e() {
			IOUtil.serialize(config, configFile);
		}};
		
		showFrame(config);
	}

	private static Config getConfig(final File configFile) {
		Config config;
		if (configFile.exists()) {
			try {
				config = IOUtil.deserialize(configFile);
			} catch (Exception e1) {
				config = new Config();
			}
		} else {
			config = new Config();
		}
		config.init();
		return config;
	}

	private static void showFrame(Config config) {

		AppFrame frame = new AppFrame("Console-q");
		
		Container cp = frame.getContentPane();
		cp.setLayout(new BorderLayout());
		JTabbedPane tabbedPane = tabbedPane(config);
		cp.add(tabbedPane,BorderLayout.CENTER);
		
		menuBar(frame,config);
		
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}


	private static void menuBar(AppFrame frame, Config config) {
		frame.getMenu(AppFrame.MENU_FILE).add(SwingUtil.menuItem("Exit",'X', SystemUtil.exit));
		
		JMenu editMenu = frame.getMenu(AppFrame.MENU_EDIT);
		editMenu.add(SwingUtil.menuItem("Preference",'P', Commands.preferenceDialog(frame,config)));
		editMenu.add(SwingUtil.menuItem("Add Tab",'A', Commands.addTabDialog(frame,config)));
	}

	private static JTabbedPane tabbedPane(final Config config) {
		final JTabbedPane tabbedPane = new JTabbedPane();
		
		final ArrayList<Invoker> invokers = new ArrayList<Invoker>();
		
		for (Console console : config.consoles) {
			Invoker invoker = Registry.getInvoker(console, config);

			JPanel pane = new JPanel();
			pane.setLayout(new BorderLayout());
			tabbedPane.add(console.name,pane);

			invokers.add(invoker);
			pane.add(consolePanel(
					invoker
			),BorderLayout.CENTER);
			
			Configurator configurator = Registry.getConfigurator(console, config);
			pane.add(configurator.detailPane(console),BorderLayout.NORTH);
		}

		
		KeyboardHandler.mapPressed('R', new F0<Boolean>(){public Boolean e() {
			if (
					KeyboardHandler.isPressed(KeyboardHandler.LSHIFT)
					&& KeyboardHandler.isPressed(KeyboardHandler.LALT)
					&& KeyboardHandler.isPressed(KeyboardHandler.LCTRL)
					) {
				DesktopUI4.beep(1);
				invokers.get(tabbedPane.getSelectedIndex()).restart();
				return false;
			}
			return true;
		}});
		
		// Selected
		if (config.selected!=null && config.selected < config.consoles.size()) {
			tabbedPane.setSelectedIndex(config.selected);
		}
		
		tabbedPane.addChangeListener(new ChangeListener() {public void stateChanged(ChangeEvent e) {
			config.selected = tabbedPane.getSelectedIndex();
			config.saveF.e();
		}});
		
		return tabbedPane;
	}

	private static Component consolePanel(Invoker invoker) {
		ConsolePane ta = new ConsolePane() {
			public P1<String> createNormalOut() {
				return decorateTaOut(super.createNormalOut());
			}

			@Override
			public P1<String> createErrOut() {
				return decorateTaOut(super.createErrOut());
			}
			
		};
//		invoker.getControls
		return panel_border(scrollPane(ta),controls(invoker,ta));
	}

	private static JComponent controls(final Invoker invoker, final ConsolePane ta) {
		invoker.setTextArea(ta);
		final JButton btnStart = new JButton("Start");

		final JButton btnStop = new JButton("Stop");
		final JButton btnClear = SwingUtil.btn("Clear", new P0() {public void e() {
			ta.setText("");
		}});
//		btnStop.setEnabled(false);
		final JButton btnRestart = new JButton("Restart");
		btnRestart.setEnabled(false);
		
		invoker.onStart(new P0() {public void e() {
			btnStart.setEnabled(false);
			btnRestart.setEnabled(true);
		}});
		invoker.onStop(new P0() {public void e() {
			btnStart.setEnabled(true);
			btnRestart.setEnabled(false);
		}});
		
		final P0 startF = new P0() {public void e() {
			invoker.start();
		}};
		btnStart.addActionListener(SwingUtil.toActionListener(startF));

		final P0 stopF = new P0() {public void e() {
			invoker.stop();
		}};
		btnStop.addActionListener(SwingUtil.toActionListener(stopF));
		

		final P0 restartF = new P0() {public void e() {
			invoker.restart();
		}};
		btnRestart.addActionListener(SwingUtil.toActionListener(restartF));
		
		return panel(btnStart,btnRestart,btnStop, btnClear);
	}

	private static P1<String> decorateTaOut(final P1<String> normalOut) {
		return observeP1(normalOut, "The server is running at ", new P0() {public void e() {
			DesktopUI4.beep(2);
		}});
	}

	public static P1<String> observeP1(final P1<String> normalOut, final String str, final P0 p0) {
		return new P1<String>() {public void e(String obj) {
			normalOut.e(obj);
			if (obj.contains(str)) {
				ThreadUtil.run(p0);
			}
		}};
	}

//	public static class Build {
//		public static void main(String[] args) {
//			BuildUtil.buildApp(GaeInvoker.class);
//		}
//	}
}
